{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "import paddle\n",
    "import paddle.fluid as fluid\n",
    "from paddle.fluid.dygraph import Linear\n",
    "import numpy as np\n",
    "import utils\n",
    "\n",
    "import matplotlib\n",
    "%matplotlib inline\n",
    "import matplotlib.pyplot as plt\n",
    "from IPython import display\n",
    "from PIL import Image"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "def draw_line(costs, learning_rate):\n",
    "    \"\"\"\n",
    "    动态绘制训练中costs的曲线\n",
    "    :param costs: 记录了训练过程的cost变化的list\n",
    "    \"\"\"\n",
    "    plt.clf()\n",
    "    plt.plot(costs)\n",
    "    plt.title(\"Learning rate = %f\" % (learning_rate))\n",
    "    plt.ylabel('cost')\n",
    "    plt.xlabel('iterations')\n",
    "    plt.pause(0.05)\n",
    "    display.clear_output(wait=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_data():\n",
    "    \"\"\"\n",
    "    数据预处理\n",
    "    \"\"\"\n",
    "    # 获取原始数据\n",
    "    train_x_ori, train_y_set, test_x_ori, test_y_set, classes = utils.load_data_sets()\n",
    "    # m_train: 训练集样本数量\n",
    "    m_train = train_x_ori.shape[0]\n",
    "    # m_test: 测试集样本数量\n",
    "    m_test = test_x_ori.shape[0]\n",
    "    # 图片样本长宽像素数量\n",
    "    num_px_x = train_x_ori.shape[1]\n",
    "    num_px_y = train_x_ori.shape[2]\n",
    "\n",
    "    # 定义输入数据维度，注意样本图像是3通道\n",
    "    DATA_DIM = num_px_x * num_px_y * 3\n",
    "\n",
    "    # 转换数据形状为\n",
    "    train_x_flatten = train_x_ori.reshape(m_train, -1)\n",
    "    test_x_flatten = test_x_ori.reshape(m_test, -1)\n",
    "\n",
    "    # 归一化处理\n",
    "    train_x_set = train_x_flatten / 255\n",
    "    test_x_set = test_x_flatten / 255\n",
    "\n",
    "    # 合并数据\n",
    "    train_set = np.hstack((train_x_set, train_y_set.T))\n",
    "    test_set = np.hstack((test_x_set, test_y_set.T))\n",
    "\n",
    "    return train_set, test_set, DATA_DIM, classes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 读取数据集以及相关参数\n",
    "global TRAIN_SET\n",
    "global TEST_SET\n",
    "global DATA_DIM\n",
    "global CLASSES\n",
    "TRAIN_SET, TEST_SET, DATA_DIM, CLASSES = get_data()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "def read_data(data_set):\n",
    "    \"\"\"\n",
    "    构造reader\n",
    "    :param data_set: 要获取的数据的数据集\n",
    "    :return: reader: 用户返回训练数据及数据标签的生成器(generator)\n",
    "    \"\"\"\n",
    "    def reader():\n",
    "        \"\"\"\n",
    "        一个reader生成器\n",
    "        :return: 每次训练数据及数据标签\n",
    "        data[:-1]: 训练数据\n",
    "        data[-1:]: 数据标签\n",
    "        \"\"\"\n",
    "        for data in data_set:\n",
    "            yield data[:-1], data[-1:]\n",
    "    return reader"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义reader\n",
    "# 定义buf_size和batch_size大小\n",
    "buf_size = 1000\n",
    "batch_size = 256\n",
    "\n",
    "# 训练集reader\n",
    "train_reader = fluid.io.batch(\n",
    "    reader=paddle.reader.shuffle(\n",
    "        reader=read_data(TRAIN_SET),\n",
    "        buf_size=buf_size\n",
    "    ),\n",
    "    batch_size=batch_size\n",
    ")\n",
    "# 测试集reader\n",
    "test_reader = fluid.io.batch(\n",
    "    reader=paddle.reader.shuffle(\n",
    "        reader=read_data(TEST_SET),\n",
    "        buf_size=buf_size\n",
    "    ),\n",
    "    batch_size=batch_size\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义多层感知器分类器\n",
    "class MultilayerPerceptron(fluid.dygraph.Layer):\n",
    "    def __init__(self,name_scope):\n",
    "        super(MultilayerPerceptron, self).__init__(name_scope)\n",
    "        # 隐藏层1，全连接层，输出大小为20，激活函数为relu\n",
    "        self.hidden1 = Linear(input_dim=DATA_DIM, output_dim=20, act='relu')\n",
    "        # 隐藏层2，全连接层，输出大小为7，激活函数为relu\n",
    "        self.hidden2 = Linear(input_dim=20, output_dim=7, act='relu')\n",
    "        # 隐藏层3，全连接层，输出大小为5，激活函数为relu\n",
    "        self.hidden3 = Linear(input_dim=7, output_dim=5, act='relu')\n",
    "        # 输出层，全连接层，输出大小为10，对应结果的十个类别，激活函数为softmax\n",
    "        self.fc = Linear(input_dim=5, output_dim=2, act='softmax')\n",
    "            \n",
    "    def forward(self,x):\n",
    "        x = self.hidden1(x)\n",
    "        x = self.hidden2(x)\n",
    "        x = fluid.layers.dropout(x, dropout_prob=0.5)\n",
    "        x = self.hidden3(x)\n",
    "        x = self.fc(x)\n",
    "        return x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义飞桨动态图工作环境\n",
    "with fluid.dygraph.guard():\n",
    "    # 实例化模型\n",
    "    # 定义多层感知器分类器\n",
    "    model = MultilayerPerceptron('catornocat')\n",
    "    \n",
    "    # 开启模型训练模式\n",
    "    model.train()\n",
    "    # 使用Adam优化器\n",
    "    # 学习率为0.000075\n",
    "    opt = fluid.optimizer.Adam(learning_rate=0.000075, parameter_list=model.parameters())\n",
    "    # 迭代次数设为2500\n",
    "    EPOCH_NUM = 2500\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "with fluid.dygraph.guard():\n",
    "    # 记录每次的损失值，用于绘图\n",
    "    costs = []\n",
    "    # 定义外层循环\n",
    "    for pass_num in range(EPOCH_NUM):\n",
    "        # 定义内层循环\n",
    "        for batch_id,data in enumerate(train_reader()):\n",
    "            # 调整数据shape使之适合模型\n",
    "            images = np.array([x[0].reshape(DATA_DIM) for x in data],np.float32)\n",
    "            labels = np.array([x[1] for x in data]).astype('int64').reshape(-1,1)\n",
    "            \n",
    "            # 将numpy数据转为飞桨动态图variable形式\n",
    "            image = fluid.dygraph.to_variable(images)\n",
    "            label = fluid.dygraph.to_variable(labels)\n",
    "            \n",
    "            # 前向计算\n",
    "            predict = model(image)\n",
    "\n",
    "            # 计算损失\n",
    "            # 使用交叉熵损失函数\n",
    "            loss = fluid.layers.cross_entropy(predict,label)\n",
    "            avg_loss = fluid.layers.mean(loss)\n",
    "\n",
    "            # 计算精度\n",
    "            # acc = fluid.layers.accuracy(predict,label)\n",
    "            \n",
    "            # 绘图\n",
    "            costs.append(avg_loss.numpy()[0])\n",
    "            draw_line(costs, 0.000075)\n",
    "\n",
    "            # 反向传播\n",
    "            avg_loss.backward()\n",
    "            # 最小化loss,更新参数\n",
    "            opt.minimize(avg_loss)\n",
    "            # 清除梯度\n",
    "            model.clear_gradients()\n",
    "\n",
    "    # 保存模型文件到指定路径\n",
    "    fluid.save_dygraph(model.state_dict(), 'catornocat')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "index 0, truth 0, infer 0\n",
      "index 1, truth 1, infer 1\n",
      "index 2, truth 1, infer 1\n",
      "index 3, truth 1, infer 0\n",
      "index 4, truth 1, infer 1\n",
      "index 5, truth 1, infer 1\n",
      "index 6, truth 0, infer 0\n",
      "index 7, truth 0, infer 1\n",
      "index 8, truth 1, infer 1\n",
      "index 9, truth 1, infer 1\n",
      "index 10, truth 1, infer 0\n",
      "index 11, truth 1, infer 1\n",
      "index 12, truth 1, infer 1\n",
      "index 13, truth 1, infer 1\n",
      "index 14, truth 1, infer 1\n",
      "index 15, truth 0, infer 0\n",
      "index 16, truth 0, infer 1\n",
      "index 17, truth 1, infer 0\n",
      "index 18, truth 0, infer 1\n",
      "index 19, truth 0, infer 0\n",
      "index 20, truth 1, infer 1\n",
      "index 21, truth 1, infer 1\n",
      "index 22, truth 1, infer 0\n",
      "index 23, truth 1, infer 0\n",
      "index 24, truth 1, infer 0\n",
      "index 25, truth 1, infer 0\n",
      "index 26, truth 1, infer 1\n",
      "index 27, truth 1, infer 0\n",
      "index 28, truth 1, infer 1\n",
      "index 29, truth 1, infer 1\n",
      "index 30, truth 1, infer 0\n",
      "index 31, truth 0, infer 0\n",
      "index 32, truth 0, infer 0\n",
      "index 33, truth 0, infer 0\n",
      "index 34, truth 0, infer 1\n",
      "index 35, truth 0, infer 1\n",
      "index 36, truth 1, infer 1\n",
      "index 37, truth 1, infer 0\n",
      "index 38, truth 1, infer 0\n",
      "index 39, truth 1, infer 1\n",
      "index 40, truth 0, infer 0\n",
      "index 41, truth 1, infer 1\n",
      "index 42, truth 1, infer 1\n",
      "index 43, truth 1, infer 0\n",
      "index 44, truth 0, infer 0\n",
      "index 45, truth 0, infer 0\n",
      "index 46, truth 1, infer 0\n",
      "index 47, truth 1, infer 1\n",
      "index 48, truth 0, infer 0\n",
      "index 49, truth 0, infer 0\n",
      "test accuracy 64.0%\n"
     ]
    }
   ],
   "source": [
    "# 模型评估\n",
    "with fluid.dygraph.guard():\n",
    "    # 读取模型\n",
    "    # 参数为保存模型参数的文件地址\n",
    "    model_dict, _ = fluid.load_dygraph('catornocat')\n",
    "    # 加载模型参数\n",
    "    model.load_dict(model_dict)\n",
    "    #评估模式\n",
    "    model.eval()\n",
    "    \n",
    "    # 读取测试集数据\n",
    "    data = next(test_reader())\n",
    "\n",
    "    # 调整数据shape使之适合模型\n",
    "    images = np.array([x[0].reshape(DATA_DIM) for x in data],np.float32)\n",
    "    labels = np.array([x[1] for x in data]).astype('int64').reshape(1, -1)[0]\n",
    "    \n",
    "    # 将numpy数据转为飞桨动态图variable形式\n",
    "    image = fluid.dygraph.to_variable(images)\n",
    "    \n",
    "    # 前向计算\n",
    "    predict = model(image)\n",
    "\n",
    "    # 统计预测结果\n",
    "    # 将预测结果转为numpy数据类型\n",
    "    predict = predict.numpy()\n",
    "    predict = np.argmax(predict, axis = 1)\n",
    "    \n",
    "    # 记录预测正确的样本数量\n",
    "    num = 0\n",
    "    for index in range(len(predict)):\n",
    "        if labels[index] == predict[index]:\n",
    "            num += 1    \n",
    "        print(\"index {}, truth {}, infer {}\".format(index, labels[index], predict[index]))\n",
    "    print(\"test accuracy {}%\".format(num/len(predict)*100))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "The label of this picture is 1.0, 1 means it's a cat picture, 0 means not \n",
      "You predict that it's a cat picture. \n",
      "Congrats!\n"
     ]
    }
   ],
   "source": [
    "# 使用单张图片测试\n",
    "# 预览测试图片\n",
    "index = 11\n",
    "image = np.reshape(TEST_SET[index][:-1], (64, 64, 3))\n",
    "plt.imshow(image)\n",
    "plt.show()\n",
    "print(\n",
    "        \"\\nThe label of this picture is \" + str(TEST_SET[index, -1])\n",
    "        + \", 1 means it's a cat picture, 0 means not \"\n",
    "        + \"\\nYou predict that it's a \"\n",
    "        + CLASSES[int(predict[index])].decode(\"utf-8\")\n",
    "        + \" picture. \\nCongrats!\"\n",
    "    )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}